import { Matrix4 } from "../../utils/Matrix4";
import { Primitives } from "../../utils/Primitives";
import { TextrueUtil } from "../../utils/TextureUtil";
import { Util } from "../../utils/Util";
import { WebGLUtil } from "../../utils/WebGLUtil";
import { Node } from "../node/Node";
import { Render } from "../Render";
import { WebglTemplateBase } from "./WebglTemplateBase";

/*
 * @Author: Snow
 * @Date: 2021-10-12 10:16:49
 * @Description: 太阳系
 */
export class TemplateSunSystem extends WebglTemplateBase {
    protected override initProgram(): void {
        this.vsSource = `
            attribute vec4 a_position;
            attribute vec4 a_color;
            
            uniform mat4 u_matrix;
            
            varying vec4 v_color;
            
            void main() {
                // Multiply the position by the matrix.
                gl_Position = u_matrix * a_position;
                
                // Pass the color to the fragment shader.
                v_color = a_color;
            }
        `;

        this.fsSource = `
            precision mediump float;

            // Passed in from the vertex shader.
            varying vec4 v_color;
            
            uniform vec4 u_colorMult;
            uniform vec4 u_colorOffset;
            
            void main() {
                gl_FragColor = v_color * u_colorMult + u_colorOffset;
            }
        `;
        super.initProgram();
    }

    protected override initBuffers(): void {
        super.initBuffers();
        const gl = Render.GL;


        const sphereBufferInfo = Primitives.createFlattenedFunc(Primitives.createSphereVertices)(gl, 10, 12, 6);
        const cubeBufferInfo = Primitives.createFlattenedFunc(Primitives.createCubeVertices)(gl, 20);
        const coneBufferInfo = Primitives.createFlattenedFunc(Primitives.createTruncatedConeVertices)(gl, 10, 0, 20, 12, 1, true, false);


        //let bufferInfo = WebGLUtil.createBufferInfoFromArrays(gl, arrays);

        let worldNode = new Node();
        worldNode.name = "worldNode";
        let sunSystemNode = new Node();
        sunSystemNode.name = "sunSystemNode";
        let sunNode = new Node();
        sunNode.name = "sunNode";
        let earthSystemNode = new Node();
        earthSystemNode.name = "earthSystemNode";
        let earthNode = new Node();
        earthNode.name = "earthNode";
        let moonNode = new Node();
        moonNode.name = "moonNode";

        worldNode.addChild(sunSystemNode);
        sunSystemNode.addChild(sunNode);
        sunSystemNode.addChild(earthSystemNode);
        earthSystemNode.addChild(earthNode);
        earthSystemNode.addChild(moonNode);

        sunSystemNode.localMatrix = Matrix4.translation(0,0,0);
        
        earthSystemNode.localMatrix = Matrix4.translation(100,0,0);

        sunNode.localMatrix = Matrix4.scaling(5, 5, 5);  // sun a the center
        sunNode.drawInfo = {
            uniforms: {
                u_colorOffset: [0.6, 0.6, 0, 1], // yellow
                u_colorMult: [0.4, 0.4, 0, 1],
                u_matrix: Matrix4.identity()
            },
            programInfo: this.programInfo,
            bufferInfo: sphereBufferInfo,
        };

        earthNode.localMatrix = Matrix4.scaling(2, 2, 2);
        earthNode.drawInfo = {
            uniforms: {
                u_colorOffset: [0.2, 0.5, 0.8, 1],  // blue-green
                u_colorMult: [0.8, 0.5, 0.2, 1],
                u_matrix: Matrix4.identity()
            },
            programInfo: this.programInfo,
            bufferInfo: sphereBufferInfo,
        };

        moonNode.localMatrix = Matrix4.translation(30, 0, 0);  // moon 20 units from the earth
        moonNode.localMatrix = Matrix4.multiply(moonNode.localMatrix, Matrix4.scaling(0.5, 0.5, 0.5));
        moonNode.drawInfo = {
            uniforms: {
                u_colorOffset: [0.6, 0.6, 0.6, 1],  // gray
                u_colorMult: [0.1, 0.1, 0.1, 1],
                u_matrix: Matrix4.identity()
            },
            programInfo: this.programInfo,
            bufferInfo: sphereBufferInfo,
        };

        let cameraAngleRadians = Util.degToRad(0);
        let fieldOfViewRadians = Util.degToRad(60);
        let cameraHeight = 50;

        let textures = [
            TextrueUtil.makeStripeTexture(gl, { color1: "#FFF", color2: "#CCC", }),
            TextrueUtil.makeCheckerTexture(gl, { color1: "#FFF", color2: "#CCC", }),
            TextrueUtil.makeCircleTexture(gl, { color1: "#FFF", color2: "#CCC", }),
        ];

        let objects = [
            sunSystemNode,
            //earthSystemNode,
        ];

        

        var objectsToDraw = [
            sunNode,
            earthNode,
            moonNode,
        ];

        let drawScene = () => {
            let time = this.ts;
            time = time * 0.5 + 5;
            WebGLUtil.resizeCanvasToMatchDisplaySize(gl);
            // Clear the canvas AND the depth buffer.
            gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

            // Compute the projection matrix
            let aspect = gl.canvas.clientWidth / gl.canvas.clientHeight;
            var projectionMatrix = Matrix4.perspective(fieldOfViewRadians, aspect, 1, 2000);

            // Compute the camera's matrix using look at.
            //往Z轴上方看去
            let cameraPosition = [0, -200, 0];
            let target = [0, 0, 0];
            let up = [0, 0, 1];
            let cameraMatrix = Matrix4.lookAt(cameraPosition, target, up);

            // Make a view matrix from the camera matrix.
            let viewMatrix = Matrix4.invert(cameraMatrix);

            let viewProjectionMatrix = Matrix4.multiply(projectionMatrix, viewMatrix);

            
            let daySpeed:number = 0.001 * 365;
            
            /// 公转
            earthSystemNode.localMatrix = Matrix4.multiply(Matrix4.rotateY(daySpeed/360),earthSystemNode.localMatrix);
            //earthSystemNode.localMatrix = Matrix4.multiply(Matrix4.rotateY(0.01),earthSystemNode.localMatrix);
            // 自转
            earthNode.localMatrix = Matrix4.multiply(earthNode.localMatrix,Matrix4.rotateY(daySpeed));
            
            moonNode.localMatrix = Matrix4.multiply(Matrix4.rotateY(daySpeed/30),moonNode.localMatrix);
            
            // for (let index = 0; index < objects.length; index++) {
            //     const node = objects[index];
            //     node.localMatrix = Matrix4.multiply(Matrix4.rotateY(0.01),node.localMatrix);
            //     //node.localMatrix = Matrix4.multiply(node.localMatrix,Matrix4.rotateY(0.01));
            // }

            sunSystemNode.updateWorldMatrix();

            // console.log("sunSystemNode",sunSystemNode.worldMatrix);
            // console.log("sunNode",sunNode.worldMatrix);
            // console.log("earthSystemNode",earthSystemNode.worldMatrix);
            // console.log("earthNode",earthNode.worldMatrix);
            // console.log("moonNode",moonNode.worldMatrix);

            gl.useProgram(this.programInfo.program);

            for (let index = 0; index < objectsToDraw.length; index++) {
                const nodeToDraw = objectsToDraw[index];
                // Setup all the needed buffers and attributes.

                WebGLUtil.setBuffersAndAttributes(gl, nodeToDraw.drawInfo.programInfo, nodeToDraw.drawInfo.bufferInfo);

                nodeToDraw.drawInfo.uniforms.u_matrix = Matrix4.multiply(viewProjectionMatrix, nodeToDraw.worldMatrix);

                // Set the uniforms that are the same for all objects.
                WebGLUtil.setUniforms(nodeToDraw.drawInfo.programInfo, nodeToDraw.drawInfo.uniforms);

                // Draw the geometry.
                gl.drawArrays(gl.TRIANGLES, 0, nodeToDraw.drawInfo.bufferInfo.numElements);
            }
        }
        this.draw = drawScene;
    }
}